//
//  BPAVPlayer.m
//  BPTV
//
//  Created by baipeng on 2018/11/15.
//  Copyright © 2018年 Apple Inc. All rights reserved.
//

#import "BPAVPlayer.h"
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>

static NSString * const AVStatus = @"status";//状态
static NSString * const AVLoadedTimeRanges = @"loadedTimeRanges";//缓存
static NSString * const AVPlayBackBufferEmpty = @"playbackBufferEmpty";//缓存中
static NSString * const AVPlayBackLikeLyToKeepUp = @"playbackLikelyToKeepUp";//缓存结束，可播放


@interface BPAVPlayer ()
@property (nonatomic,strong)AVPlayer *player;
@property(nonatomic, strong) AVPlayerItem *playerItem;
@property(nonatomic, strong) AVPlayerLayer *playerlayer;

@property(nonatomic,strong)id timeObserver;

@end

@implementation BPAVPlayer
#pragma mark - public method
+(instancetype)shareInstance{
    static BPAVPlayer *avPlayer = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        avPlayer = [[self alloc]init];
    });
    return avPlayer;
}
- (instancetype)init{
    self = [super init];
    if (self) {
        //允许锁屏播放 start  添加后台播放代码：
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setActive:YES error:nil];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];
        //以及设置app支持接受远程控制事件代码。设置app支持接受远程控制事件，
        //其实就是在dock中可以显示应用程序图标，同时点击该图片时，打开app。
        //或者锁屏时，双击home键，屏幕上方出现应用程序播放控制按钮。
        [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    }
    return self;
}

#pragma mark - 不同业务处理之间的方法以
-(void)playWithUrlString:(NSString *)urlString view:(UIView *)view frame:(CGRect)frame{
    if (kStringIsEmpty(urlString)) {
        [self showHint:@"链接为空"];
        return;
    }
    NSURL *playerItemURL = nil;
    if ([urlString hasPrefix:@"https://"] || [urlString hasPrefix:@"http://"]) {
        playerItemURL = [NSURL URLWithString:urlString];
    }else{
        playerItemURL = [NSURL fileURLWithPath:urlString];
    }
    self.urlPath = urlString;
    //删除观察者
    [self removePlayerItemObserver];
    //创建播放的资源
    self.playerItem = [[AVPlayerItem alloc]initWithURL:playerItemURL];
    //播放当前资源
    [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
    //渲染播放
    self.playerlayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    self.playerlayer.frame = frame;
    self.playerlayer.backgroundColor = [UIColor blackColor].CGColor;
    [view.layer addSublayer:self.playerlayer];
    //添加观察者
    [self addPlayerItemObserver];
    //总时间
    self.totalTime = CMTimeGetSeconds(self.playerItem.asset.duration);
    self.progress = 0.0;
    //设置锁屏播放
    [self showLockScreenTotaltime:self.totalTime andCurrentTime:0];
}
//TODO:播放
-(void)play{
    [self.player play];
}
//TODO:暂停
-(void)pause{
    [self showLockScreenProgress:CMTimeGetSeconds(self.player.currentTime)];
    [self.player pause];
}
//TODO:停止
-(void)stop{
    [self.player pause];
    [self removePlayerItemObserver];
    [self.player replaceCurrentItemWithPlayerItem:nil];
    self.player = nil;
}
//TODO:改变播放进度
-(void)seekToProgress:(CGFloat)progress{
    int32_t timeScale = self.player.currentItem.asset.duration.timescale;
    NSLog(@"timeScale=%d",timeScale);
    [self.player seekToTime:CMTimeMakeWithSeconds(progress*self.totalTime, 1) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
        NSLog(@"seekToProgress=%f,finished=%d",progress,finished);
    }];
}
#pragma mark - set/get
//TODO:是否正在播放
-(BOOL)isPlaying{
    return self.player.rate;
}


#pragma mark - observer method
//TODO:添加观察者
-(void)addPlayerItemObserver{
    //状态
    [self.player.currentItem addObserver:self forKeyPath:AVStatus options:NSKeyValueObservingOptionNew context:nil];
    //缓存
    [self.player.currentItem addObserver:self forKeyPath:AVLoadedTimeRanges options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:AVPlayBackBufferEmpty options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:AVPlayBackLikeLyToKeepUp options:NSKeyValueObservingOptionNew context:nil];
    //监控播放完成
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playBackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
    //监听进度
    kWeakSelf(self);
    self.timeObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) {
        Float64 currentSeconds = CMTimeGetSeconds(time);
        float progree = currentSeconds*1.0/weakself.totalTime;
        if (!isnan(progree)) {
            NSLog(@"start progress %f",progree);
        }
    }];
}
//TODO:删除监听
-(void)removePlayerItemObserver{
    [self.player.currentItem removeObserver:self  forKeyPath:AVStatus];
    [self.player.currentItem removeObserver:self forKeyPath:AVLoadedTimeRanges];
    [self.player.currentItem removeObserver:self forKeyPath:AVPlayBackBufferEmpty];
    [self.player.currentItem removeObserver:self forKeyPath:AVPlayBackLikeLyToKeepUp];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    [self.player removeTimeObserver:self.timeObserver];
    self.timeObserver = nil;
}





#pragma mark - private method
//TODO:结束播放通知
-(void)playBackFinished:(NSNotification *)obj{
    NSLog(@"播放结束");
    self.progress = 0.0;
    [self showLockScreenProgress:0.0];
}

#pragma mark - KVO method
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    AVPlayerItem *playerItem = object;
    NSLog(@"addobser%@",change);
    if ([keyPath isEqualToString:AVStatus]) {
        AVPlayerItemStatus status = [change[@"new"] integerValue];
        switch (status) {
            case AVPlayerItemStatusReadyToPlay:{//播放
                if (self.progress) {
                    [self seekToProgress:self.progress];
                }
                [self play];
            }
                break;
            case AVPlayerItemStatusFailed:{//失败
                NSLog(@"加载失败");
            }
                break;
            case AVPlayerItemStatusUnknown:{
                NSLog(@"未知资源");
            }
                break;
            default:
                break;
        }
    }else if ([keyPath isEqualToString:AVLoadedTimeRanges]){
        //缓存
        NSTimeInterval totalBuffer = [self availableDuration];
        NSLog(@"共缓存：%.2f",totalBuffer);
        if (totalBuffer > self.getCurrentPlayingTime+5) {//大于5s 开始播放
            [self play];
        }else{
            NSLog(@"等待缓存");
        }
    }else if ([keyPath isEqualToString:AVPlayBackBufferEmpty]){

    }else if ([keyPath isEqualToString:AVPlayBackLikeLyToKeepUp]){

    }else if ([keyPath isEqualToString:@"rate"]){
        // rate=1:播放，rate!=1:非播放
        float rate = self.player.rate;
        NSLog(@"%f",rate);
    }else if ([keyPath isEqualToString:@"currentItem"]){
        NSLog(@"new currentItem");
    }
}


//TODO:返回 当前 播放时长
- (double)getCurrentPlayingTime{
    return self.player.currentTime.value/self.player.currentTime.timescale;
}
//TODO: 返回 当前 缓存总时长
- (NSTimeInterval)availableDuration{
    NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];
    CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 获取缓冲区域
    float startSeconds = CMTimeGetSeconds(timeRange.start);
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    NSTimeInterval result = startSeconds + durationSeconds;// 计算缓冲总进度

    return result;
}







#pragma mark --- 锁屏歌曲信息
- (void)showLockScreenTotaltime:(float)totalTime andCurrentTime:(float)currentTime{
    NSMutableDictionary *songInfo = [ [NSMutableDictionary alloc] init];
    //锁屏图片
    UIImage *img;
    NSString *_lockImageName = nil;
    NSString *_lockTitle = nil;
    if ([_lockImageName hasPrefix:@"http://"] || [_lockImageName hasPrefix:@"https://"]) {
        img = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:_lockImageName]]];
    }else {
        img = [UIImage imageNamed:_lockImageName];
    }
    if (img) {
        MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc]initWithImage:img];
        [songInfo setObject: albumArt forKey:MPMediaItemPropertyArtwork ];
    }

    if (totalTime) {
        //设置歌曲时长
        [songInfo setObject:[NSNumber numberWithFloat:totalTime] forKey:MPMediaItemPropertyPlaybackDuration];
    }

    //设置已经播放时长
    [songInfo setObject:[NSNumber numberWithDouble:currentTime] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];

    //锁屏标题
    if (_lockTitle) {
        //设置歌曲题目
        [songInfo setObject:_lockTitle forKey:MPMediaItemPropertyTitle];
        //设置专辑名
        [songInfo setObject:_lockTitle forKey:MPMediaItemPropertyAlbumTitle];
    }

    [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo ];
}
- (void)showLockScreenProgress:(CGFloat)progress {
    NSMutableDictionary *songInfo = [NSMutableDictionary dictionaryWithDictionary:[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo];
    [songInfo setObject:[NSNumber numberWithDouble:progress] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];//progress*totalSeconds
    [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo ];
}




#pragma mark - Lazy loading
-(AVPlayer *)player{
    if (!_player) {
        _player = [[AVPlayer alloc]init];
        _player.volume = 1.0;//最大音量
    }
    return _player;
}











@end
